package main

import "fmt"

//接口类型的零值也用预声明的nil标识符来表示。 一个nil接口值中什么也没包裹。
//将一个接口值修改为nil将清空包裹在此接口值中的非接口值。
//
//（注意，在Go中，很多其它非接口类型的零值也使用nil标识符来表示。
//非接口类型的nil零值也可以被包裹在接口值中。
//一个包裹了一个nil非接口值的接口值不是一个nil接口值，因为它并非什么都没包裹。）
//
//因为任何类型都实现了空接口类型，所以任何非接口值都可以被包裹在任何一个空接口类型的接口值中。
//（以后，一个空接口类型的接口值将被称为一个空接口值。
//注意空接口值和nil接口值是两个不同的概念。）
//因为这个原因，空接口值可以被认为是很多其它语言中的any类型。

//下面是（使用==比较运算符）比较两个接口值的步骤：
//1.如果其中一个接口值是一个nil接口值，则比较结果为另一个接口值是否也为一个nil接口值。
//2.如果这两个接口值的动态类型不一样，则比较结果为false。
//3.对于这两个接口值的动态类型一样的情形，
//	如果它们的动态类型为一个不可比较类型，则将产生一个恐慌。
//	否则，比较结果为它们的动态值的比较结果。
//
//简而言之，两个接口值的比较结果只有在下面两种任一情况下才为true：
//1.这两个接口值都为nil接口值。
//2.这两个接口值的动态类型相同、动态类型为可比较类型、并且动态值相等。
//根据此规则，两个包裹了不同非接口类型的nil零值的接口值是不相等的。
func main() {
	var a, b, c interface{} = "abc", 123, "a" + "b" + "c"
	fmt.Println(a == b) // 第二步的情形。输出"false"。
	fmt.Println(a == c) // 第三步的情形。输出"true"。

	var x *int = nil
	var y *bool = nil
	var ix, iy interface{} = x, y
	var i interface{} = nil
	fmt.Println(ix == iy) // 第二步的情形。输出"false"。
	fmt.Println(ix == i)  // 第一步的情形。输出"false"。
	fmt.Println(iy == i)  // 第一步的情形。输出"false"。

	var s []int = nil // []int为一个不可比较类型。
	i = s
	fmt.Println(i == nil) // 第一步的情形。输出"false"。
	fmt.Println(i == i)   // 第三步的情形。将产生一个恐慌。
}
